package rankingGenerator;

import rankingGenerator.statistics.DREComparableStatistic;
import rankingGenerator.statistics.KUsefulWithProbability;
import configuration.parameters.DoubleValuedParameter;
import configuration.parameters.Parameter;

import distributedRE.model.DataBase;
import distributedRE.model.DistributedREModel;
import distributedRE.model.Query;
import distributedRE.model.QueryDatabase;
import distributedRE.model.Session;
import estimators.numberoOfDocuments.DocumentEstimator;
import estimators.numberoOfDocuments.NumberOfDocumentCalculator;

import umontreal.iro.lecuyer.probdist.HypergeometricDist;


public class UsefulDocumentsSelector extends RankingGenerator {

	
	private DocumentEstimator nodc;

	public UsefulDocumentsSelector(DocumentEstimator nodc){
		this.nodc = nodc;
	}
	
	public DREComparableStatistic calculateCostValue(Query query, DataBase dataBase,
			DistributedREModel dREModel, Session s) {
		
		long dbLimit = dataBase.getSampleResultSize();
		
		int bestK = -1;
		
		double bestProbability = -1;
		
		double probability;
		
		for (int k = 0; k < dbLimit ; k++) {
			
			probability = calculateProbability(k,query,dataBase,dREModel,s);
			
			if (probability > bestProbability){
				bestProbability = probability;
				bestK = k;
			}
			
		}
		
		return new KUsefulWithProbability(bestK,bestProbability);
		
	}

	private double calculateProbability(int k, Query query, DataBase dataBase,
			DistributedREModel dREModel, Session s) {
		
		QueryDatabase qdb = QueryDatabase.getInstance(query, dataBase, dREModel);
		
		double ret = RetrievedBy(qdb,s);
		double lastP = LastPrecision(qdb);
		
		return HypergeometricDist.prob((int)Math.round(Math.ceil(ret*lastP)), (int)Math.round(Math.ceil(ret)), (int)dataBase.getSampleResultSize(), k);
		
//		double up_prob = Mathematics.BinomialCoefficient(Math.round(ret*lastP),(long)k)*Mathematics.BinomialCoefficient(Math.round(ret*(1-lastP)),(long)(dataBase.getSampleResultSize()-k));
//		double down_prob = Mathematics.BinomialCoefficient(Math.round(ret),(long)dataBase.getSampleResultSize());
		
//		return (up_prob/down_prob);
		
	}

	private double RetrievedBy (QueryDatabase qdb, Session s) {
		
		Parameter nod; //= qdb.getParameter(Parameter.NUMBEROFDOCUMENTS);
		
//		if (nod == null){
			
			double number = nodc.estimateDocumentsRetrieved(qdb);
			
			nod = new DoubleValuedParameter(number);
			
			qdb.addParameter(Parameter.NUMBEROFDOCUMENTS, nod);
			
			return ((Double)nod.getValue()).doubleValue();
			
//		}
		
//		long samplesize = qdb.getDatabase().getSampleResultSize();
		
//		double value = ((Double)nod.getValue()).doubleValue() - samplesize;
		
//		nod = new DoubleValuedParameter(value);
		
//		qdb.addParameter(Parameter.NUMBEROFDOCUMENTS, nod);
		
//		return ((Double)nod.getValue()).doubleValue();
	}

	private double LastPrecision(QueryDatabase qdb) {

		Parameter p = qdb.getParameter(Parameter.PRECISION);
		
		return ((Double)p.getValue()).doubleValue();
		
	}

	public String toString(){
		return "Number of Useful documents Selector estimating with " + nodc.toString();
	}
	
}
